'use strict'

const path = require('path')
const Package = require('@lenovo-cli/package')
const log = require('@lenovo-cli/log')
const { spawnExec } = require('@lenovo-cli/utils')
const { SETTINGS, CACHE_DIR } = require('./const')

async function dynaExec() {
  let targetPath = process.env.CLI_TARGET_PATH
  const homePath = process.env.CLI_HOME_PATH
  let storeDir = ''
  let pkg
  log.verbose('targetPath', targetPath)
  log.verbose('homePath', homePath)
  const cmdObj = arguments[arguments.length - 1]
  const cmdName = cmdObj.name()
  const packageName = SETTINGS[cmdName] // 通过指令名映射包文件名
  const packageVersion = 'latest'
  if (!targetPath) {
    // targetPath不存在的的话，就生成缓存路径 CACHE_DIR ：dependencies
    targetPath = path.resolve(homePath, CACHE_DIR) // 生成缓存路径
    storeDir = path.resolve(targetPath, 'node_modules')
    log.verbose('targetPath', targetPath)
    log.verbose('storeDir', storeDir)
    pkg = new Package({
      targetPath,
      storeDir,
      packageName,
      packageVersion,
    })
    if (await pkg.exists()) {
      // 更新package
      await pkg.update()
    } else {
      // 安装package
      await pkg.install()
    }
  } else {
    // targetPath 存在
    pkg = new Package({
      targetPath,
      packageName,
      packageVersion,
    })
  }
  const rootFile = pkg.getRootFilePath()
  if (rootFile) {
    try {
      // 1 在当前进程中执行
      // require(rootFile).call(null, Array.from(arguments)) // require(rootFile)执行文件init/index.js, apply去执行函数，null是传入的this,

      // 2 node子进程中执行 （node多进程核心是： 创建子进程 在child_process中创建）
      // spwan 可以随着进程进行，不断的打印出过程。 (还可以通过fork方法可以放到子进程中，但是fork不支持回调，不推荐)
      // spwan 返回一个子进程对象
      const args = Array.from(arguments)
      const cmd = args[args.length - 1]
      const o = Object.create(null) // 创建没有原型链的对象
      Object.keys(cmd).forEach(key => {
        if (
          // 对args进行瘦身，单独保留_optionValues(其中的'--force')
          key === '_optionValues' ||
          (cmd.hasOwnProperty(key) && !key.startsWith('_') && key !== 'parent')
        ) {
          o[key] = cmd[key]
        }
      })
      args[args.length - 1] = o
      const code = `require('${rootFile}').call(null, ${JSON.stringify(args)})`
      const child = spawnExec('node', ['-e', code], {
        cwd: process.cwd(),
        stdio: 'inherit', // 设置了inherit，就不需要child.stdout.on来监听过程
      })
      child.on('error', e => {
        log.error(e.message)
        process.exit(1) // 当子进程抛出异常时，停掉主进程
      })
      child.on('exit', e => {
        log.verbose('命令执行成功：' + e)
        process.exit(e)
      })
    } catch (e) {
      log.error(e.message)
    }
  }
}

module.exports = dynaExec
